ThinkPHP5.1.x 代码执行漏洞分析


复现

https://tprce/index.php?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1

image_1d8ffjpn01kouopob14c9i1mt19.png-104.1kB

漏洞分析

从payload入手,在app处下断点跟入, thinkphp/library/think/Request.php 681行,处理兼容模式的url请求:

image_1d8fsee7h1red11t7d9e14omhgk1j.png-388.5kB

thinkphp/library/think/route/Rule.php 947行
image_1d8fvv9pa1aadflj4bu2b4pe81m.png-276.7kB
可以看到其以/分割,分割成模块/控制器/操作方法

路由解析,分发到对应模块/控制器/操作方法thinkphp/library/think/route/dispatch/Url.php 37行

image_1d8fu10u5a7gujrjgt18171llc9.png-345.1kB

thinkphp/library/think/route/dispatch/Module.php 84行 exec(),实例化控制器
image_1d8g15qpv1foi12mihmd1826mvr36.png-294.2kB

跟入该文件135行,该函数利用反射机制调用类方法,从而进行代码执行

1
$data = $this->app->invokeReflectMethod($instance, $reflect, $vars);

-> thinkphp/library/think/Container.php 347行 invokeFunction()
image_1d8g1mln71tog1ud81g4l2931d053j.png-387.1kB

到这里就已经任意代码执行了。

第一次接触反射机制,记录一下自己的理解,简单来说反射即根据目的地找来源,也就是根据已经实例化的对象来找其所属的类和类中的方法

以上为ThinkPHP5.1.x的rce分析,ThinkPHP5.0.x有一些差异,以后来填坑。

修复

路由解析过程中没有对控制器的命名规则进行检测,导致我们可以操作任意控制器,官方修复加了正则只允许字符传入:
image_1d8g2fr8dkjqi9g1aah1unf18dj63.png-173.9kB

参考:

  1. PHP反射机制原理与用法详解